package week01.question02;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;

/**
 * 自定义一个 Classloader，加载一个 Hello.xlass 文件，执行 hello 方法，此文件内容是一个 Hello.class 文件所有字节（x=255-x）处理后的文件。
 */
public class MyClassLoader extends ClassLoader{

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        if("Hello".equals(name)){
            byte [] bytes = readFromResource("/Hello.xlass", true);
            return defineClass(name, bytes,0, bytes.length);
        }
        return super.findClass(name);
    }

    /**
     * 从本地文件系统加载 Hello.xlass 文件
     * @param filePath 文件路径
     * @param reverse 是否反转
     * @return 返回处理过后的字节码序列
     */
    private byte[] readFromFilePath(String filePath, boolean reverse){
        try (FileInputStream fis = new FileInputStream(new File(filePath));
             BufferedInputStream bufferedInputStream = new BufferedInputStream(fis);
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            int available = bufferedInputStream.available();
            byte [] bytes = new byte[8192];
            System.out.println(available);
            int b = 0;
            while( (b=bufferedInputStream.read(bytes)) !=-1){
                baos.write(bytes,0,b);
            }
            byte[] reverseByByte = reverse? reverseByByte(baos.toByteArray()): baos.toByteArray();
            System.out.println(Arrays.toString(reverseByByte));
            return reverseByByte;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new byte[0];
    }

    /**
     * 从项目路径中加载xlass文件
     * @param resourceName resource classpath路径
     * @param reverse 是否处理
     * @return 解析之后的字节数组
     */
    private byte[] readFromResource(String resourceName, boolean reverse){
        try {
            URL resource = this.getClass().getResource(resourceName);
            byte[] bytes = Files.readAllBytes(Paths.get(resource.toURI()));
            return reverse? reverseByByte(bytes): bytes;
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new byte[0];
    }

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, URISyntaxException, IOException {
        MyClassLoader myClassLoader = new MyClassLoader();
        Object hello = myClassLoader.findClass("Hello").newInstance();
        Class<?> helloClass = hello.getClass();
        Method[] declaredMethods = helloClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            if(declaredMethod.getName().equals("hello")){
                declaredMethod.setAccessible(true);
                declaredMethod.invoke(hello, null);
                break;
            }
        }
        Method hello1 = helloClass.getDeclaredMethod("hello",  null);
        hello1.invoke(hello, null);
    }

    private byte[] reverseByByte(byte[] bytes){
        byte [] reverse = new byte[bytes.length];
        for (int i = 0; i < bytes.length; i++) {
                reverse[i]= (byte)((byte)255-bytes[i]);
        }
        return reverse;
    }
}
